package com.zy.rpc.consumer.proxy;

import com.zy.rpc.common.ask.RpcRequest;
import com.zy.rpc.common.ask.RpcResponse;
import com.zy.rpc.common.discovery.DiscoveryService;
import com.zy.rpc.common.serviceinfo.ServiceInfo;
import com.zy.rpc.consumer.config.RpcClientProperties;
import com.zy.rpc.consumer.transport.impl.NettyClientTransport;
import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

/**
 * @author zy
 * @date 2023/5/7 10:32
 */
public class ClientStubProxyFactory  {

    private static Map<Class<?>,Object> objectCahce=new HashMap<>();

    public static Object getProxy(Class<?> clazz, DiscoveryService discoveryService, RpcClientProperties rpcClientProperties) {
        return objectCahce.computeIfAbsent(clazz, clz -> {
            CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom()
                    .failureRateThreshold(50) // 设置失败率阈值
                    .waitDurationInOpenState(Duration.ofSeconds(10)) // 断路器打开后等待时间
                    .permittedNumberOfCallsInHalfOpenState(5) // 半开状态下允许的最大请求数
                    // 这个参数设置了窗口大小。窗口大小定义了用于计算失败率的滑动窗口的大小。在你的设置中，窗口大小
                    // 是 10。熔断器会根据这个窗口内的请求来计算失败率。
                    .slidingWindowSize(10)
                    .build();
            CircuitBreaker circuitBreaker = CircuitBreaker.of("myCircuitBreaker", circuitBreakerConfig);

            return Proxy.newProxyInstance(
                    clz.getClassLoader(), new Class[]{clz}, new InvocationHandler() {
                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                            ServiceInfo serviceInfo = discoveryService.discovery(clazz.getName());
                            if (serviceInfo == null) {
                                throw new RuntimeException("NULL SERVICE:404");
                            }
                            RpcRequest rpcRequest = new RpcRequest();
                            rpcRequest.setServiceName(serviceInfo.getServiceName());
                            rpcRequest.setMethod(method.getName());
                            rpcRequest.setParamsType(method.getParameterTypes());
                            rpcRequest.setParams(args);
                            // 使用熔断器执行远程调用

                            CompletableFuture<RpcResponse> rpcResponseCompletableFuture = circuitBreaker
                                    .executeSupplier(() -> {
                                        try {   
                                            return NettyClientTransport.getInstance().sendRecquest(rpcRequest, serviceInfo.getAddress(), serviceInfo.getPort());
                                        } catch (Exception e) {
                                            // 如果发生异常，返回一个默认的备用结果
                                            RpcResponse fallbackResponse = new RpcResponse();
                                            fallbackResponse.setData("Fallback data");
                                            return CompletableFuture.completedFuture(fallbackResponse);
                                        }
                                    });
                                RpcResponse rpcResponse = rpcResponseCompletableFuture.get(10, TimeUnit.SECONDS);
                            return rpcResponse.getData();
                        }
                    });
        });
    }
}
